#region game
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using FirstGame.Objects;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace GameStateManagement
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class GameplayScreen : GameScreen
    {
        ContentManager content;
        float pauseAlpha;
        private GameTime _gameTime;
        private Player _player;
        private Texture2D _enemy;
        private Texture2D _playerProjectile;
        private const float MaxSpeed = 5f;
        private const float ProjectileDelayValue = 0.2f;
        private readonly List<Projectile> _projectiles = new List<Projectile>();
        private TimeSpan _lastProjectileFired = new TimeSpan(0);
        private readonly TimeSpan _projectileDelay;
        private TimeSpan _lastEnemySpawn = new TimeSpan(0);
        private readonly TimeSpan _enemySpawnDelay = TimeSpan.FromSeconds(4);
        private List<Enemy> _enemies = new List<Enemy>();
        public GameplayScreen()
        {
            _projectileDelay = TimeSpan.FromSeconds(ProjectileDelayValue);
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");
            content.RootDirectory = "Content";
            // Create a new SpriteBatch, which can be used to draw textures.
            //spriteBatch = new SpriteBatch(graphics);
            _player = new Player(content.Load<Texture2D>("Sprites/PlayerShip"), new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2, ScreenManager.GraphicsDevice.Viewport.Height / 2), new Vector2(0, 0));
            _playerProjectile = content.Load<Texture2D>("Sprites/PlayerProjectile");
            _enemy = content.Load<Texture2D>("Sprites/EnemyShip");
            Thread.Sleep(1000);
            ScreenManager.Game.ResetElapsedTime();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);
            // Gradually fade in or out depending on whether we are covered by the pause screen.
            pauseAlpha = coveredByOtherScreen ? Math.Min(pauseAlpha + 1f / 32, 1) : Math.Max(pauseAlpha - 1f / 32, 0);

            if (IsActive)
            {
                _gameTime = gameTime;
                UpdateSprite();
                UpdateProjectiles();
                UpdateEnemies(gameTime);
                DetectCollisions();
            }
        }

        public override void HandleInput(InputState input)
        {
           if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {
                _player.Speed = DirectionalDetect(gamePadState);
                AttackDetect(gamePadState);
            }
        }
        
        private float SpeedBoostDetect(GamePadState gamePadState)
        {
            if (gamePadState.IsConnected)
            {
                float triggerPressValue = gamePadState.Triggers.Right;
                if (triggerPressValue > 0)
                {
                    GamePad.SetVibration(PlayerIndex.One, triggerPressValue / 2, triggerPressValue / 2);
                    return MaxSpeed + MaxSpeed * triggerPressValue;
                }
            }
            GamePad.SetVibration(PlayerIndex.One, 0, 0);
            return MaxSpeed;
        }

        private Vector2 DirectionalDetect(GamePadState gamePadState)
        {
            float maxSpeed = SpeedBoostDetect(gamePadState);
            float xSpeed = gamePadState.ThumbSticks.Left.X * maxSpeed;
            float ySpeed = -gamePadState.ThumbSticks.Left.Y * maxSpeed;
            return new Vector2(xSpeed, ySpeed);
        }

        private void SpawnEnemy()
        {
            Enemy enemy = new Enemy(_enemy);
            enemy.Spawn(ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height);
            _enemies.Add(enemy);
        }

        private void AttackDetect(GamePadState gamePadState)
        {
            float xSpeed = gamePadState.ThumbSticks.Right.X;
            float ySpeed = -gamePadState.ThumbSticks.Right.Y;
            if (xSpeed > 0.25f || ySpeed > 0.25f || xSpeed < -0.25f || ySpeed < -0.25f)
            {
                Projectile projectile = new Projectile(_playerProjectile, new Vector2(_player.Position.X + _player.Sprite.Width / 2 - _playerProjectile.Width / 2, _player.Position.Y + _player.Sprite.Height / 2 - _playerProjectile.Width / 2), new Vector2(xSpeed, ySpeed));
                if (_gameTime.TotalGameTime - _lastProjectileFired > _projectileDelay)
                {
                    _projectiles.Add(projectile);
                    _lastProjectileFired = _gameTime.TotalGameTime;
                }
            }
        }

        private void UpdateEnemies(GameTime gameTime)
        {
            if (gameTime.TotalGameTime - _lastEnemySpawn > _enemySpawnDelay)
            {
                SpawnEnemy();
                _lastEnemySpawn = gameTime.TotalGameTime;
            }

            Coords min = new Coords(-_enemy.Width, -_enemy.Height);
            Coords max = new Coords(ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height);

            for (int x = 0; x < _enemies.Count; x++)
            {
                Enemy enemy = _enemies[x];
                if (enemy.IsEnemyOutOfBounds(min, max))
                {
                    _enemies.Remove(enemy);
                    x++;
                }

            }
        }

        private void UpdateProjectiles()
        {
            Coords min = new Coords(-_playerProjectile.Width, -_playerProjectile.Height);
            Coords max = new Coords(ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height);

            for (int x = 0; x < _projectiles.Count; x++)
            {
                Projectile projectile = _projectiles[x];
                if (projectile.IsProjectileOutOfBounds(min, max))
                {
                    _projectiles.Remove(projectile);
                    x++;
                }
            }
        }

        private void UpdateSprite()
        {
            Coords max = new Coords(ScreenManager.GraphicsDevice.Viewport.Width - _player.Sprite.Width,
                ScreenManager.GraphicsDevice.Viewport.Height - _player.Sprite.Height);
            Coords min = new Coords(0, 0);
            _player.UpdatePlayer(min, max);
        }

        private void DetectCollisions()
        {
            //List<Enemy> hitEnemies = from enemy in _enemies
            //                 from projectile in _projectiles
            //                 where enemy.BoundingBox.Intersects(projectile.BoundingBox)
            //                 select enemy;
            //List<Enemy> hitEnemies = _enemies.FindAll(x => x.BoundingBox.Intersects(_projectiles.Any(y)));
            //_enemies.RemoveAll(
            //    x => x.BoundingBox.Intersects(_projectiles.FindAll(y => y.BoundingBox.Intersects(x.BoundingBox))));

            //for (int i = 0; i < _projectiles.Count; i++)
            //{
            //    Projectile projectile = _projectiles[i];

            //    List<Enemy> hitEnemies = from(_enemies.)
            //        (_enemies.Select(x => x.BoundingBox.Intersects(projectile.BoundingBox)));


            //for 
            //{

            //}
            for (int i = 0; i < _enemies.Count; i++)
            {
                if (_enemies[i].BoundingBox.Intersects(_player.BoundingBox))
                {
                    //TODO - you died
                }
                for (int n = 0; n < _projectiles.Count; n++)
                {
                    if (_enemies[i].BoundingBox.Intersects(_projectiles[n].BoundingBox))
                    {
                        _enemies.Remove(_enemies[i]);
                        _projectiles.Remove(_projectiles[n]);
                        i++;
                        n++;
                    }
                }
            }
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.Black, 0, 0);

            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

            spriteBatch.Begin();
            for (int x = 0; x < _projectiles.Count; x++)
            {
                spriteBatch.Draw(_projectiles[x].Sprite, _projectiles[x].Position, Color.White);
            }
            spriteBatch.Draw(_player.Sprite, _player.Position, Color.White);
            for (int y = 0; y < _enemies.Count; y++)
            {
                spriteBatch.Draw(_enemies[y].Sprite, _enemies[y].Position, Color.White);
            }            
            spriteBatch.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }
    }
}
#endregion

/*
#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
#endregion

namespace GameStateManagement
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        ContentManager content;
        SpriteFont gameFont;

        Vector2 playerPosition = new Vector2(100, 100);
        Vector2 enemyPosition = new Vector2(100, 100);

        Random random = new Random();

        float pauseAlpha;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }


        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");

            gameFont = content.Load<SpriteFont>("gamefont");

            // A real game would probably have more content than this sample, so
            // it would take longer to load. We simulate that by delaying for a
            // while, giving you a chance to admire the beautiful loading screen.
            Thread.Sleep(1000);

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            ScreenManager.Game.ResetElapsedTime();
        }


        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            if (IsActive)
            {
                // Apply some random jitter to make the enemy move around.
                const float randomization = 10;

                enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
                enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;

                // Apply a stabilizing force to stop the enemy moving off the screen.
                Vector2 targetPosition = new Vector2(
                    ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2,
                    200);

                enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);

                // TODO: this game isn't very fun! You could probably improve
                // it by inserting something more interesting in this space :-)
            }
        }


        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {
                // Otherwise move the player position.
                Vector2 movement = Vector2.Zero;

                if (keyboardState.IsKeyDown(Keys.Left))
                    movement.X--;

                if (keyboardState.IsKeyDown(Keys.Right))
                    movement.X++;

                if (keyboardState.IsKeyDown(Keys.Up))
                    movement.Y--;

                if (keyboardState.IsKeyDown(Keys.Down))
                    movement.Y++;

                Vector2 thumbstick = gamePadState.ThumbSticks.Left;

                movement.X += thumbstick.X;
                movement.Y -= thumbstick.Y;

                if (movement.Length() > 1)
                    movement.Normalize();

                playerPosition += movement * 2;
            }
        }


        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            // This game has a blue background. Why? Because!
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.CornflowerBlue, 0, 0);

            // Our player and enemy are both actually just text strings.
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

            spriteBatch.Begin();

            spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);

            spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
                                   enemyPosition, Color.DarkRed);

            spriteBatch.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }


        #endregion
    }
}
*/